import os
import sys
import time
import requests
import urllib.request as request
from bs4 import BeautifulSoup
import pandas as pd
import PyQt5 as Qt
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import QVideoWidget

class getWords(object):
    """ 获取单词类 """
    def researchVocabulary(self,englishWord):
        """ 通过有道词典翻译单词 """
        try:
            # 利用GET获取输入单词的网页信息
            r = requests.get(
                url='http://dict.youdao.com/w/%s/#keyfrom=dict2.top' % englishWord)
            # 利用BeautifulSoup将获取到的文本解析成HTML
            soup = BeautifulSoup(r.text, "lxml")

            vocabuary = {"word": englishWord}

            # 获取中文
            chinese = soup.find(class_='trans-container')('ul')[0]('li')
            # 获取音标
            soundmark = soup.find(class_='phonetic').text
            # 获取读音
            voiceURL,voicePath = self.getVoice(voiceType=0, englishWord=englishWord)
            
            vocabuary["cahinese"] = [item.text for item in chinese]
            vocabuary["soundmark"] = soundmark
            vocabuary["voiceURL"] = voiceURL
            vocabuary["voicePath"] = voicePath

            return vocabuary
        except:
            print("查词错误！")
            vocabuary = None
        finally:
            return vocabuary
    

    def getVoice(self,voiceType=0, englishWord="vocabulary"):
            '''
            私有函数，生成发音的目标URL
            http://dict.youdao.com/dictvoice?type=0&audio=
            '''
            url = r'http://dict.youdao.com/dictvoice?type=' + str(
                voiceType) + r'&audio=' + englishWord
            filePath = 'voice\\'+englishWord+'.mp3'
            try:
                request.urlretrieve(url, filename=filePath)
            except Exception as e:
                print("Sorry, there is a error!\n",e)
                filePath = None
            finally:
                return url, filePath
            print("voice downed!")
            return url,filePath


class manWindow(QMainWindow):
    """ 主窗口 """
    def __init__(self):
        super().__init__()
        self.log_ = {}
        self.logs = pd.DataFrame()
        self.headLeabels = ['word', 'chinese', 'soundmark', 'voiceURL', 'voicePath']
        self.currentVocabularies = pd.DataFrame()
        self.vocabuaryRoot = "vocabularise"
        # a = os.walk(self.vocabuaryRoot)
        self.vocabularyWarehose = os.listdir(self.vocabuaryRoot)
        self.word_dic = {}
        self.initUI()
        # 实例化查单词对象
        self.GW = getWords()

    def initUI(self):
        """ 初始化方法 """
        # 全局布局
        wid = QWidget(self)
        self.setCentralWidget(wid)
        self.layout = QHBoxLayout()
        wid.setLayout(self.layout)

        # 左边垂直布局
     ###
        self.vLayout = QVBoxLayout()
        # 左边控件
        lwg = QWidget(self)

        lwg.setLayout(self.vLayout)
        self.layout.addWidget(lwg)

        self.tabWidget = QTabWidget(self)
        self.vLayout.addWidget(self.tabWidget)

        self.tab1 = QWidget()
        self.tabWidget.addTab(self.tab1, "背单词")
        self.tab2 = QWidget()
        self.tabWidget.addTab(self.tab2, "录入单词")

      ## 设置tab1 背单词
        self.model_BDC =  QStandardItemModel(0, 5)
        self.vLayout01 = QVBoxLayout()
        self.tab1.setLayout(self.vLayout01)

        self.label0 = QLabel(self)
        self.label0.setText("Chinese to English \n选择背单词词库：")
        self.vLayout01.addWidget(self.label0)

        self.comb2 = QComboBox(self)
        self.vLayout01.addWidget(self.comb2)
        for i in self.vocabularyWarehose:
            self.comb2.addItem(i)
        # self.comb2.currentIndexChanged.connect(self.selectBDCvocabularies)

        self.wg011 = QWidget(self)
        self.vLayout01.addWidget(self.wg011)
        self.hlayout011 = QHBoxLayout()
        self.wg011.setLayout(self.hlayout011)

        self.btn7 = QPushButton("选择词库")
        self.hlayout011.addWidget(self.btn7)
        self.btn7.clicked.connect(self.selectBDCvocabularies)

        self.lab6 = QLabel("记录：")
        self.hlayout011.addWidget(self.lab6)

        self.comb4 = QComboBox(self)
        self.hlayout011.addWidget(self.comb4)

        self.wg012 = QWidget(self)
        self.vLayout01.addWidget(self.wg012)
        self.hlayout012 = QHBoxLayout()
        self.wg012.setLayout(self.hlayout012)

        self.comb3 = QComboBox(self)
        self.hlayout012.addWidget(self.comb3)
        # self.comb3.currentIndexChanged.connect()

        self.btn9 = QPushButton("选择单词组")
        self.hlayout012.addWidget(self.btn9)
        self.btn9.clicked.connect(self.selectWordGroup)

        self.btn8 = QPushButton("开始背这组单词")
        self.vLayout01.addWidget(self.btn8)
        self.btn8.clicked.connect(self.startBDC)

        self.label1 = QLabel(self)
        self.label1.setText("中文释义：")
        self.vLayout01.addWidget(self.label1)

        self.tEdit2 = QTextEdit()
        self.vLayout01.addWidget(self.tEdit2)
        self.tEdit2.setReadOnly(True)

        # 单词播放器  PyQt5_QMediaPlayer()
        self.btn6 = QPushButton(self)
        self.btn6.setText('单词读音')
        self.vLayout01.addWidget(self.btn6)
        self.btn6.clicked.connect(self.btn6Clicked)

        self.label2 = QLabel(self)
        self.label2.setText("拼写单词：")
        self.vLayout01.addWidget(self.label2)
        
        self.eidtLine1 = QLineEdit()
        self.vLayout01.addWidget(self.eidtLine1)
        self.eidtLine1.setFont(QFont('Arial', 20))
        self.eidtLine1.returnPressed.connect(self.checkWord)

        self.btn1 = QPushButton(self)
        self.btn1.setText("检查")
        self.vLayout01.addWidget(self.btn1)
        self.btn1.clicked.connect(self.checkWord)

        self.label3 = QLabel(self)
        self.label3.setText("拼写结果：")
        self.vLayout01.addWidget(self.label3)

        self.eidtLine2 = QTextEdit()
        self.vLayout01.addWidget(self.eidtLine2)
      ##

     ##设置tab2 录入单词
        self.model_LDC = QStandardItemModel(0, 5)
        self.model_LDC.setHorizontalHeaderLabels(self.headLeabels)

        self.vLayout02 = QVBoxLayout()
        self.tab2.setLayout(self.vLayout02)

        self.lab1 = QLabel("输入英文单词：")
        self.vLayout02.addWidget(self.lab1)

        self.lEdit1 = QLineEdit()
        self.vLayout02.addWidget(self.lEdit1)
        self.lEdit1.setFont(QFont('Arial', 20))
        self.lEdit1.returnPressed.connect(self.selectWord)

        self.btn2 = QPushButton("联网查询")
        self.vLayout02.addWidget(self.btn2)
        self.btn2.clicked.connect(self.selectWord)

        self.lab2 = QLabel("查询结果：")
        self.vLayout02.addWidget(self.lab2)

        self.tEdit1 = myTextEdit(self)
        self.vLayout02.addWidget(self.tEdit1)
        # self.tEdit1.keyPressEvent.connect(self.btn3clicked)

        self.btn3 = QPushButton("录入词表")
        self.vLayout02.addWidget(self.btn3)
        self.btn3.clicked.connect(self.btn3clicked)

      ##
     ###

        # 右边垂直布局
     ###
        self.vLayout1 = QVBoxLayout()
        # 右边控件
        rwg = QWidget(self)
        rwg.setLayout(self.vLayout1)
        self.layout.addWidget(rwg)

        self.lab3 = QLabel("选择词库：")
        self.vLayout1.addWidget(self.lab3)

        self.comb1 = QComboBox()
        self.vLayout1.addWidget(self.comb1)
        self.selectVocabulars()
        self.comb1.currentIndexChanged.connect(self.readVocabulary)

        self.lab4 = QLabel("当前词库：{}".format(""))
        self.vLayout1.addWidget(self.lab4)

        self.lab5 = QLabel("单词列表")
        self.vLayout1.addWidget(self.lab4)


       ## 单词列表
        #实例化表格视图，设置模型为自定义的模型
        self.tableView = QTableView()
        self.vLayout1.addWidget(self.tableView)
       ##

        # self.btn4 = QPushButton(self)
        # self.btn4.setText("合并重复")
        # self.vLayout1.addWidget(self.btn4)

        self.btn5 = QPushButton(self)
        self.btn5.setText("存入词库")
        self.vLayout1.addWidget(self.btn5)
        self.btn5.clicked.connect(self.saveVocabularise)
     ###

        # 设置主窗体大小
        self.resize(1000, 600)
        # 设置窗体名
        self.setWindowTitle('背单词')
        # 设置log
        self.setWindowIcon(QIcon("logo.png"))
        # 显示窗体
        self.show()
    
    def closeEvent(self, event):
        "重写关闭窗口事件，保存日志"
        reply = QMessageBox.question(self, 'Message',
                                    "Are you sure to quit?", QMessageBox.Yes |
                                    QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            if bool(1-self.logs.empty):
                self.logs.to_csv("log.csv",index=None)
            event.accept()
        else:
            event.ignore()

    def selectVocabulars(self):
        "选择词库"
        
        for i in self.vocabularyWarehose:
            self.comb1.addItem(i)

    def readVocabulary(self):
        ''' 读取选择的词库 '''
        # 检查词典csv是否存在，若存在就读取
        self.dictionaryPath = "vocabularise\\{}".format(self.comb1.currentText())
        if os.path.exists(self.dictionaryPath):
            self.currentVocabularies = pd.read_csv(self.dictionaryPath)
            self.lab4.setText("当前词库：{}  词量：{}".format(self.comb1.currentText(),str(self.currentVocabularies.shape[0])))
        else:
            QMessageBox.warning(
                self, "Exception", "词典 vocabularise\\{self.comb1.currentText()}不存在！", QMessageBox.Yes | QMessageBox.No)

    def btn6Clicked(self):
        "发音"
        try:
            mp3file = self.word_BDC["voicePath"]
            self.player = QMediaPlayer(self)
            self.player.setMedia(QMediaContent(QUrl.fromLocalFile(mp3file)))
            # self.player.prepare_audio(mp3file)
            self.player.setVolume(50)
            # self.player = QSound(mp3file)
            self.player.play()
        except Exception as e:
            QMessageBox.warning(
                self, "Exception"+str(e), "请先查找单词！", QMessageBox.Yes | QMessageBox.No)
        finally:
            return
        
    def selectBDCvocabularies(self):
        "选择背单词词库"
        # 从背单词记录中选取
        self.currentRowIndex = [0,10]
        self.ckName_BDC = self.comb2.currentText()
        self.ck_BDC = pd.read_csv('vocabularise\\{}'.format(self.ckName_BDC))
        self.wordGroupIndex = [[i,i+10] for i in range(self.ck_BDC.shape[0]) if i % 10 == 0]
        self.wordGroupIndex[-1][-1] = self.ck_BDC.shape[0]
        self.comb3.clear()
        for i in self.wordGroupIndex:
            self.comb3.addItem(str(i))

        self.model_BDC.clear()
        self.model_BDC.setHorizontalHeaderLabels(self.headLeabels)
        self.wordGroup = self.ck_BDC[self.currentRowIndex[0] : self.currentRowIndex[1]]
        for index,word in self.wordGroup.iterrows():
            self.model_BDC.appendRow([QStandardItem(str(i)) for i in word])

        if self.log_:
            self.logs = pd.read_csv("log.csv")
            self.logs = self.logs.append(self.log_, ignore_index=True)
            self.log_ = {}
            self.logs.to_csv("log.csv", index=None)
        else:
            pass
        
        self.tableView.setModel(self.model_BDC)
        self.logs = pd.read_csv("log.csv")
        # print(self.log_, self.logs)
        self.ck_Log = self.logs[self.logs["vocabulary"]==self.ckName_BDC]
        self.comb4.clear()
        for a, i in self.ck_Log.iterrows():
            self.comb4.addItem(str(i["time"])+' '+str(i["location"]))
        
    def selectWordGroup(self):
        '选取单词组'
        self.currentRowIndex = eval(self.comb3.currentText())
        self.model_BDC.clear()
        self.model_BDC.setHorizontalHeaderLabels(self.headLeabels)
        self.wordGroup = self.ck_BDC[self.currentRowIndex[0]: self.currentRowIndex[1]]
        for index, word in self.wordGroup.iterrows():
            self.model_BDC.appendRow([QStandardItem(str(i)) for i in word])

        self.tableView.setModel(self.model_BDC)
        
    def startBDC(self):
        "开始目前wordGroup中的背单词"
        self.currentWordGroupIndex = 0
        self.word_BDC = {k:v for k, v in zip(self.headLeabels, self.wordGroup.iloc[self.currentWordGroupIndex])}
        self.tEdit2.clear()
        for i in eval(self.word_BDC["chinese"]):
            self.tEdit2.append("<font color='blue' size='4'>{}</font>".format(i))
        self.btn6Clicked()
        self.eidtLine1.setFocus()
        self.errWordGroup = pd.DataFrame()
        # 更新日志
        self.log_ = {'vocabulary':self.ckName_BDC, 
                    'time'       :time.strftime("%Y.%m.%d %H:%M", time.localtime())[2:], 
                    'location'   :str(self.currentRowIndex)}
        self.logs.append(self.log_, ignore_index=True)
        
    def checkWord(self):
        "检查单词"
        if self.wordGroup.shape[0]-1 != -1:
            if self.word_BDC['word'] == self.eidtLine1.text().strip():
                self.eidtLine2.append(
                    "<font color='green' size='10'>{}</font>".format('拼写正确！加油！'))
                self.eidtLine2.append(
                    "<font color='green' size='10'>{}</font>".format('正确单词：   '+self.word_BDC['word']))
                self.eidtLine2.append(
                    "<font color='green' size='10'>{}</font>".format('你的单词：   '+self.eidtLine1.text().strip()))
                self.currentWordGroupIndex += 1
                if self.wordGroup.shape[0]-1 >= self.currentWordGroupIndex:
                    self.word_BDC = {k: v for k, v in zip(self.headLeabels, self.wordGroup.iloc[self.currentWordGroupIndex])}
                    self.tEdit2.clear()
                    for i in eval(self.word_BDC["chinese"]):
                        self.tEdit2.append(
                            "<font color='blue' size='4'>{}</font>".format(i))
                    self.btn6Clicked()
                else:
                    if bool(1-self.errWordGroup.empty):
                        self.eidtLine2.append('开始复习该组拼写错误单词！')
                        self.wordGroup = self.errWordGroup
                        self.errWordGroup = pd.DataFrame()
                        self.currentWordGroupIndex = 0
                        self.word_BDC = {k: v for k, v in zip(
                            self.headLeabels, self.wordGroup.iloc[self.currentWordGroupIndex])}
                        self.tEdit2.clear()
                        for i in eval(self.word_BDC["chinese"]):
                            self.tEdit2.append(
                                "<font color='blue' size='4'>{}</font>".format(i))
                        self.btn6Clicked()
                    else:
                        self.eidtLine2.append('该组单词已学完，请开始下一组！')
            else:
                if self.wordGroup.shape[0]-1 >= self.currentWordGroupIndex:
                    self.eidtLine2.append(
                        "<font color='red' size='10'>{}</font>".format('拼写错误！努力！'))
                    self.eidtLine2.append(
                        "<font color='red' size='10'>{}</font>".format('正确单词：   '+self.word_BDC['word']))
                    self.eidtLine2.append(
                        "<font color='red' size='10'>{}</font>".format('你的单词：   '+self.eidtLine1.text().strip()))

                    if self.errWordGroup.empty:
                        self.errWordGroup = pd.DataFrame(self.word_BDC, index=[0])
                    else:
                        self.errWordGroup = self.errWordGroup.append(
                            self.word_BDC, ignore_index=True)
                else:
                    if bool(1-self.errWordGroup.empty):
                        self.eidtLine2.append('开始复习该组拼写错误单词！') 
                        self.wordGroup = self.errWordGroup # 装进学习词组
                        self.errWordGroup = pd.DataFrame()
                        self.currentWordGroupIndex = 0
                        self.word_BDC = {k: v for k, v in zip(
                            self.headLeabels, self.wordGroup.iloc[self.currentWordGroupIndex])}
                        self.tEdit2.clear()
                        for i in eval(self.word_BDC["chinese"]):
                            self.tEdit2.append(
                                "<font color='blue' size='4'>{}</font>".format(i))
                        self.btn6Clicked()
                    else:
                        self.eidtLine2.append('该组单词已学完，请开始下一组！')
                          
        else:
            self.eidtLine2.append('该组单词空，请开检查！')
        self.eidtLine1.clear()
        self.eidtLine1.setFocus()

    def setWordList(self,vocabulary="vocabularise"):
        ''' 显示单词列表 '''
        ## 单词列表
        # 设置数据层次结构，4行4列
        shape = self.dictionary.shape
        self.model = QStandardItemModel(shape[0], shape[1]+1)
        #设置水平方向四个头标签文本内容
        headLeabels = [" "]
        for i in self.dictionary.columns.values.tolist():  # 提取列名转列表
            headLeabels.append(str(i))

        self.model.setHorizontalHeaderLabels(headLeabels)

        for row in range(shape[0]):
            for column in range(shape[1]+1):
                if column == 0:
                    item = QStandardItem(str(self.dictionary.index[row]))
                else:
                    item = QStandardItem(
                        str(self.dictionary.values[row][column-1]))
                # print(self.dictionary.values[row][column])
                #设置每个位置的文本值
                self.model.setItem(row, column, item)

        #实例化表格视图，设置模型为自定义的模型
        self.tableView.setModel(self.model)
        #todo 优化1 表格填满窗口
        #水平方向标签拓展剩下的窗口部分，填满表格
        self.tableView.horizontalHeader().setStretchLastSection(True)
        # #水平方向，表格大小拓展到适当的尺寸
        # self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
       ##

    def insertWord_model_LDC(self):
        if self.word_dic:
            v = self.word_dic.values()
            self.model_LDC.appendRow([QStandardItem(str(i))
                                      for i in self.word_dic.values()])
            self.tableView.setModel(self.model_LDC)
        else:
            QMessageBox.warning(
                self, "Exception", "请先查找单词！", QMessageBox.Yes | QMessageBox.No)
    
    def selectWord(self):
        ''' 查询单词 '''
        # self.lEdit1.focusOutEvent(QFocusEvent(QEvent.FocusOut))
        self.tEdit1.clear()
        word = self.lEdit1.text().strip()
        self.word_dic = self.GW.researchVocabulary(word)
        if self.word_dic:
            for k, v in self.word_dic.items():
                self.tEdit1.append("<font color='green' size='10'>{}</font>".format(str(k)+'      :'+str(v)))# self.tEdit1.home(True)
            self.tEdit1.setFocus()
            tc = self.tEdit1.textCursor()
            # tc.movePosition(QTextCursor.PreviousBlock,QTextCursor.KeepAnchor)  # 移动光标
            cursor_pos = QTextCursor.Start  # 文档开头
            #QTextCursor.MoveAnchor    将锚点移动到与光标本身相同的位置(默认)
            #QTextCursor.KeepAnchor    将锚固定在原处
            tc.movePosition(cursor_pos, QTextCursor.MoveAnchor,1)   # 锚点与光标之间的内容会被选中
            self.tEdit1.setTextCursor(tc)  # 修改完光标之后 还得反向设置回文本编辑器te
        else:
            self.tEdit1.append("<font color='red' size='10'>查词错误，请检查拼写错误或联网状态！</font>")


        # cursor.endEditBlock()

    def btn3clicked(self):
        ''' 录入词表 '''
        self.insertWord_model_LDC()
        self.lEdit1.setFocus()
        self.lEdit1.clear()

    def saveVocabularise(self):
        ''' 存入词库 '''
        m = self.tableView.model()
        if m != None:
            df = pd.DataFrame({i:i for i in self.headLeabels},index = [0])
            for i in range(10000):
                row = []
                if m.item(i) != None:
                    for j in range(5):
                        item = m.item(i, j)
                        # print(item.text())
                        row.append(item.text())
                    d = dict(zip(self.headLeabels, row))
                    df = df.append([d],ignore_index=True)
                else:
                    break  
            pre_df = pd.read_csv(
                'vocabularise\\{}'.format(self.comb1.currentText()))
            dfs = pre_df.append(df)
            dfss = dfs.drop_duplicates(subset=['word'],keep='first')
            rowindex = dfss[(dfss["word"]) == "word"].index.tolist()
            dfsss = dfss.drop(rowindex)
            # if self.currentVocabularies.empty == False:
            #     df = self.currentVocabularies.append(df)
            dfsss.to_csv('vocabularise\\{}'.format(self.comb1.currentText()),index=None)
        else:
            QMessageBox.warning(
                self, "Exception", "请先添加单词！", QMessageBox.Yes | QMessageBox.No)


class myTextEdit(QTextEdit):
    "重构QtextEdit方法"
    def __init__(self, parent):
        QTextEdit.__init__(self)
        self.parent = parent

    def keyPressEvent(self, event):
        QTextEdit.keyPressEvent(self, event)
        if event.key() == Qt.Key_Return: # 如果按了Enter
            self.parent.btn3clicked()
        if event.key() == Qt.Key_Shift:  # 如果按了shift
            self.parent.lEdit1.setFocus()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainW = manWindow()
    themes = ["theme\\blue.txt",
              "theme\\Customizations.txt",
              "theme\\darkblack.txt",
              "theme\\DarkOrangeQss.txt",
              "theme\\yellowDark.txt"]
    with open(themes[0]) as file:
        theme = file.readlines()
        theme = ''.join(theme).strip('\n')
        app.setStyleSheet(theme)

    sys.exit(app.exec_())
